package org.mp3weezel.strands.services;

import java.util.HashMap;
import java.util.Map;

import org.mp3weezel.strands.StrandsAPI;
import org.mp3weezel.strands.StrandsServiceException;
import org.mp3weezel.strands.domain.DetailedAlbum;
import org.mp3weezel.strands.domain.SimpleAlbumList;
import org.mp3weezel.strands.domain.SimpleArtistList;
import org.mp3weezel.strands.domain.SimpleGenreList;
import org.mp3weezel.strands.domain.SimpleTrackList;

/**
 * Catalog services retrieve data for artists, albums, and tracks in the
 * MyStrands catalog.
 * 
 * <ul>
 * <li><b>Lookup services</b></li>
 * <ul>
 * <li>{@link #lookupArtists(String[])} Returns metadata for the given artist
 * ids.</li>
 * <li>{@link #lookupAlbums(String[], String)} - Returns metadata for the given
 * album ids. </li>
 * <li>{@link #lookupTracks(String[], String)} - Returns metadata for the given
 * track ids.</li>
 * <li>{@link #lookupAlbumTracks(String[], String)} - Returns a list of the
 * tracks on the given album.</li>
 * <li>{@link #lookupArtistAlbums(String[], int, int, String)} - Returns a list
 * of albums in the MyStrands catalog associated with the given artist.</li>
 * </ul>
 * <li><b>Search Services</b><br>
 * Search looks for the searchText in both the name and metadata fields of the
 * given item. If you want to find items by name, see resultion Services.<br>
 * <br>
 * </li>
 * <ul>
 * <li>{@link #searchArtists(String, int, int)} - Searches for artists in the
 * MyStrands catalog matching the given search text.</li>
 * <li>{@link #searchAlbums(String, int, int)} - Searches for albums in the
 * MyStrands catalog matching the given search text.</li>
 * <li>{@link #searchTracks(String, int, int)} - Searches for tracks in the
 * MyStrands catalog matching the given search text.</li>
 * </ul>
 * 
 * <li><b>Browse Services</b></li>
 * <ul>
 * <li>{@link #listGenres(int, int)} - Returns a list of MyStrands genre names.</li>
 * <li>{@link #browseGenre(String, String, int, int)} - Returns a list of
 * albums in the given genre matching the specified browse criteria.</li>
 * <li>{@link #browseArtists(String, int, int)} - Returns a list of artists
 * matching the specified browse criteria.</li>
 * <li>{@link #browseAlbums(String, int, int)} - Returns a list of albums
 * matching the specified browse criteria.</li>
 * </ul>
 * 
 * <li><b>Recent Items</b></li>
 * <ul>
 * <li>{@link #recentAlbums(int)} - Returns the specified number of most
 * recently released albums in the MyStrands catalog.</li>
 * <li>{@link #recentTracks(int)} - Returns the specified number of most
 * recently released tracks in the MyStrands catalog.</li>
 * </ul>
 * 
 * <li><b>Random Items</b></li>
 * <ul>
 * <li>{@link #randomTracks(int)} - Returns the specified number of randomly
 * selected tracks from the MyStrands catalog.</li>
 * </ul>
 * </ul>
 * 
 * @author Christian Humer
 */
public class CatalogService extends AbstractService {

	public CatalogService(StrandsAPI api) {
		super(api);
	}

	/**
	 * Returns metadata for the given artist ids.
	 * 
	 * @param id(s)
	 * @return List<SimpleArtistList>
	 * @throws StrandsServiceException
	 */
	public SimpleArtistList lookupArtists(String[] ids) throws StrandsServiceException {
		assertNotEmpty("ids", ids);
		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("id", ids);
		return (SimpleArtistList) request("/lookup/artists", parameter);
	}

	/**
	 * Returns metadata for the given album ids.
	 * 
	 * Remark: A real user alias parameter causes the return to contain
	 * UserPurchaseURI elements if possible.
	 * 
	 * @param id(s)
	 * @param (alias)
	 *            optional
	 * 
	 * @return List<SimpleAlbumList>
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList lookupAlbums(String[] ids, String alias)
			throws StrandsServiceException {
		assertNotEmpty("ids", ids);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("id", ids);
		parameter.put("alias", new String[] { alias });
		return (SimpleAlbumList) request("/lookup/albums", parameter);
	}

	/**
	 * Returns metadata for the given track ids.
	 * 
	 * Remark: A real user alias parameter causes the return to contain
	 * UserPurchaseURI elements if possible.
	 * 
	 * @param id(s)
	 * @param (alias)
	 *            optional
	 * @return List<SimpleTrackList>
	 * @throws StrandsServiceException
	 */
	public SimpleTrackList lookupTracks(String[] ids, String alias)
			throws StrandsServiceException {
		assertNotEmpty("ids", ids);
		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("id", ids);
		parameter.put("alias", new String[] { alias });
		return (SimpleTrackList) request("/lookup/tracks", parameter);
	}

	/**
	 * Returns a list of the tracks on the given album.
	 * 
	 * Remark: A real user alias parameter causes the return to contain
	 * userPurchaseURI elements if possible.
	 * 
	 * @param id(s)
	 * 
	 * @param (alias)
	 *            optional
	 * @return List<DetailedAlbum>
	 * @throws StrandsServiceException
	 */
	public DetailedAlbum lookupAlbumTracks(String[] ids, String alias)
			throws StrandsServiceException {
		assertNotEmpty("ids", ids);
		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("id", ids);
		parameter.put("alias", new String[] { alias });
		return (DetailedAlbum) request("/lookup/album/tracks", parameter);
	}

	/**
	 * Returns a list of albums in the MyStrands catalog associated with the
	 * given artist.
	 * 
	 * Remark: A real user alias parameter causes the return to contain
	 * userPurchaseURI elements if possible.
	 * 
	 * @param id(s)
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param (alias)
	 *            optional
	 * @return List<DetailedAlbum>
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList lookupArtistAlbums(String[] ids, int num, int skip,
			String alias) throws StrandsServiceException {
		assertNotEmpty("ids", ids);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("id", ids);
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleAlbumList) request("/lookup/artist/albums", parameter);
	}

	/**
	 * Searches for artists in the MyStrands catalog matching the given search
	 * text.
	 * 
	 * @param searchText
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleArtistList searchArtists(String searchText, int num, int skip)
			throws StrandsServiceException {
		assertNotEmpty("searchText", searchText);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleArtistList) request("/search/artists", parameter);
	}

	/**
	 * Searches for albums in the MyStrands catalog matching the given search
	 * text.
	 * 
	 * @param searchText
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList searchAlbums(String searchText, int num, int skip)
			throws StrandsServiceException {

		assertNotEmpty("searchText", searchText);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleAlbumList) request("/search/albums", parameter);
	}

	/**
	 * Searches for tracks in the MyStrands catalog matching the given search
	 * text.
	 * 
	 * @param searchText
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleTrackList searchTracks(String searchText, int num, int skip)
			throws StrandsServiceException {
		assertNotEmpty("searchText", searchText);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleTrackList) request("/search/tracks", parameter);
	}

	/**
	 * Returns a list of MyStrands genre names.
	 * 
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleGenreList listGenres(int num, int skip) throws StrandsServiceException {
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleGenreList) request("/list/genres", parameter);
	}

	/**
	 * Returns a list of albums in the given genre matching the specified browse
	 * criteria.
	 * 
	 * @param genre
	 *            is a MyStrands genre name
	 * @param searchText
	 *            a letter A-Z or MISC for non-alphabetic items
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList browseGenre(String genre, String searchText,
			int num, int skip) throws StrandsServiceException {
		assertNotEmpty("searchText", searchText);
		assertNotEmpty("genre", genre);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("genre", new String[] { genre });
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleAlbumList) request("/browse/genre", parameter);
	}

	/**
	 * Returns a list of artists matching the specified browse criteria.
	 * 
	 * @param searchText
	 *            a letter A-Z or MISC for non-alphabetic items
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleArtistList browseArtists(String searchText, int num, int skip)
			throws StrandsServiceException {
		assertNotEmpty("searchText", searchText);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleArtistList) request("/browse/artists", parameter);
	}

	/**
	 * Returns a list of albums matching the specified browse criteria.
	 * 
	 * @param searchText
	 *            a letter A-Z or MISC for non-alphabetic items
	 * @param num
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @param skip
	 *            where num and skip can be used to page through the results
	 *            (default num=10, skip=0).
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList browseAlbums(String searchText, int num, int skip)
			throws StrandsServiceException {
		assertNotEmpty("searchText", searchText);
		assertNotNegative("num", num);
		assertNotNegative("skip", skip);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("searchText", new String[] { searchText });
		parameter.put("num", new String[] { String.valueOf(num) });
		parameter.put("skip", new String[] { String.valueOf(skip) });
		return (SimpleAlbumList) request("/browse/albums", parameter);
	}

	/**
	 * Returns the specified number of most recently released albums in the
	 * MyStrands catalog.
	 * 
	 * @param num
	 *            where the default num=10.
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleAlbumList recentAlbums(int num) throws StrandsServiceException {
		assertNotNegative("num", num);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("num", new String[] { String.valueOf(num) });
		return (SimpleAlbumList) request("/recent/albums", parameter);
	}

	/**
	 * Returns the specified number of most recently released tracks in the
	 * MyStrands catalog.
	 * 
	 * @param num
	 *            where the default num=10.
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleTrackList recentTracks(int num) throws StrandsServiceException {
		assertNotNegative("num", num);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("num", new String[] { String.valueOf(num) });
		return (SimpleTrackList) request("/recent/tracks", parameter);
	}

	/**
	 * Returns the specified number of randomly selected tracks from the
	 * MyStrands catalog.
	 * 
	 * @param num
	 *            where the default num=1.
	 * @return
	 * @throws StrandsServiceException
	 */
	public SimpleTrackList randomTracks(int num) throws StrandsServiceException {
		assertNotNegative("num", num);

		Map<String, String[]> parameter = new HashMap<String, String[]>();
		parameter.put("num", new String[] { String.valueOf(num) });
		return (SimpleTrackList) request("/random/tracks", parameter);
	}

}
